﻿using StockModel;
using TechnicalIndicators.DateBased;
using TechnicalIndicators.Points;
using TechnicalIndicators.QuotationBased;
using Utils;
using System;

namespace StockAnalyst2.Chart
{
	internal class Generator2
	{
		#region Attributes

		private readonly BarGenerator _lastValueBarGenerator;
		private readonly LastValueGenerator _lastValueGenerator;
		private readonly OpenPercentageGenerator _openPercentageGenerator;
		private readonly BidAskAverageGenerator _bidAskAverageGenerator;
		private readonly BidAskGenerator _bidAskGenerator;
		private readonly MovingAverage _sma1Generator;
		private readonly MovingAverage _sma2Generator;
		private readonly MovingAverage _sma3Generator;

		private readonly Stochastic _stochastic;
		private readonly GapGenerator _gapGenerator;

		private readonly VolumeGenerator _volumeGenerator;
		private readonly Accumulator _volumeAccumulator;
		private readonly AccumulatedVolumeGenerator _totalVolumeGenerator;
		private readonly MovingAverage _volumeAverageGenerator;

		private readonly ObservableCollection2<DatedSeriePoint> _auxVolume;
		private ReadWriteLockedObservableCollection<Quotation> _currentSource;

		#endregion

		#region Properties

		public ChartData Data { get; private set; }

		#endregion

		#region Public Methods

		public Generator2()
		{
			_auxVolume = new ObservableCollection2<DatedSeriePoint>();

			this.Data = new ChartData();

			_lastValueBarGenerator = new BarGenerator(this.Data.LastValueBar.Data);
			_lastValueGenerator = new LastValueGenerator(this.Data.LastValue.Data);
			_openPercentageGenerator = new OpenPercentageGenerator(this.Data.LastValuePercentage.Data);
			_bidAskAverageGenerator = new BidAskAverageGenerator(this.Data.BidAskAverage.Data);
			_bidAskGenerator = new BidAskGenerator(this.Data.BidAsk.Data);
			_sma1Generator = new MovingAverage(this.Data.SMA1.Data);
			_sma2Generator = new MovingAverage(this.Data.SMA2.Data);
			_sma3Generator = new MovingAverage(this.Data.SMA3.Data);
			_stochastic = new Stochastic(this.Data.Stochastic.Data);
			_gapGenerator = new GapGenerator(this.Data.Gap.Data);
			_volumeGenerator = new VolumeGenerator(_auxVolume);
			_volumeAccumulator = new Accumulator(this.Data.Volume.Data);
			_totalVolumeGenerator = new AccumulatedVolumeGenerator(this.Data.TotalVolume.Data);
			_volumeAverageGenerator = new MovingAverage(this.Data.AverageVolume.Data);
		}

		public void CreateChart(ReadWriteLockedObservableCollection<Quotation> source)
		{
			this.Clear();

			_currentSource = source;

			// Volume is always generated as it creates the X-axis
			this.GenerateVolume();

			// Chart source is always generated
			ReadWriteLockedObservableCollection<DatedSeriePoint> mainSerie = this.GenerateSource();

			_lastValueBarGenerator.Source = mainSerie;
			_lastValueBarGenerator.Configure(new TimeSpan(0, 5, 0));
			_lastValueBarGenerator.Start();

			if (this.Data.Options.Bid.IsEnabled)
			{
				_bidAskGenerator.Source = _currentSource;
				_bidAskGenerator.Configure(true);
				_bidAskGenerator.Start();
			}

			if (this.Data.Options.Gap.IsEnabled)
			{
				_gapGenerator.Source = _currentSource;
				_gapGenerator.Configure(true);
				_gapGenerator.Start();
			}

			this.GenerateSourceDependentSeries(mainSerie);
		}

		public void Clear()
		{
			_lastValueBarGenerator.Clear();
			_lastValueGenerator.Clear();
			_openPercentageGenerator.Clear();
			_bidAskAverageGenerator.Clear();
			_bidAskGenerator.Clear();
			_sma1Generator.Clear();
			_sma2Generator.Clear();
			_sma3Generator.Clear();
			_stochastic.Clear();
			_gapGenerator.Clear();
			_volumeGenerator.Clear();
			_volumeAccumulator.Clear();
			_totalVolumeGenerator.Clear();
			_volumeAverageGenerator.Clear();
		}

		#endregion

		#region Private Methods

		private ReadWriteLockedObservableCollection<DatedSeriePoint> GenerateSource()
		{
			if (this.Data.Options.LastValue.IsEnabled || this.Data.Options.DataSource == ChartSource.LastValue)
			{
				_lastValueGenerator.Source = _currentSource;
				_lastValueGenerator.Configure(true);
				_lastValueGenerator.Start();
			}

			if (this.Data.Options.BidAskAverage.IsEnabled || this.Data.Options.DataSource == ChartSource.BidAskAverage)
			{
				_bidAskAverageGenerator.Source = _currentSource;
				_bidAskAverageGenerator.Configure(true);
				_bidAskAverageGenerator.Start();
			}

			_openPercentageGenerator.Source = _currentSource;
			_openPercentageGenerator.Start();

			return this.Data.Options.DataSource == ChartSource.LastValue ? _lastValueGenerator.Serie : _bidAskAverageGenerator.Serie;
		}

		private void GenerateSourceDependentSeries(ReadWriteLockedObservableCollection<DatedSeriePoint> source)
		{
			if (this.Data.Options.SMA1.IsEnabled)
			{
				_sma1Generator.Source = source;
				_sma1Generator.Configure(this.Data.Options.SMA1.Parameter1Value);
				_sma1Generator.Start();
			}

			if (this.Data.Options.SMA2.IsEnabled)
			{
				_sma2Generator.Source = source;
				_sma2Generator.Configure(this.Data.Options.SMA2.Parameter1Value);
				_sma2Generator.Start();
			}

			if (this.Data.Options.SMA3.IsEnabled)
			{
				_sma3Generator.Source = source;
				_sma3Generator.Configure(this.Data.Options.SMA3.Parameter1Value);
				_sma3Generator.Start();
			}

			if (this.Data.Options.Stochastic.IsEnabled)
			{
				_stochastic.Source = source;
				_stochastic.Configure(this.Data.Options.Stochastic.Parameter1Value);
				_stochastic.Start();
			}
		}

		private void GenerateVolume()
		{
			_volumeGenerator.Source = _currentSource;
			_volumeGenerator.Start();

			_volumeAccumulator.Source = _volumeGenerator.Serie;
			_volumeAccumulator.Configure(this.Data.Options.Volume.Parameter1Value);
			_volumeAccumulator.Start();

			if (this.Data.Options.TotalVolume.IsEnabled)
			{
				_totalVolumeGenerator.Source = _currentSource;
				_totalVolumeGenerator.Start();
			}

			if (this.Data.Options.AverageVolume.IsEnabled)
			{
				_volumeAverageGenerator.Source = _volumeAccumulator.Serie;
				_volumeAverageGenerator.Configure(this.Data.Options.AverageVolume.Parameter1Value);
				_volumeAverageGenerator.Start();
			}
		}

		#endregion

	}
}
